package cn.easyutil.easystart.redis.config;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import java.util.Set;

import cn.easyutil.easystart.redis.service.RedisService;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

@Service
public class DefaultRedisServiceImpl implements RedisService {
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public void delExpireTime(String key) {
        redisTemplate.persist(key);
    }

    @Override
    public void delete(String... keys) {
        redisTemplate.delete(Arrays.asList(keys));
    }

    @Override
    public String get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    @Override
    public List<String> getArray(String key) {
        return redisTemplate.opsForList().range(key, 0, -1);
    }

    @Override
    public String getArray(String key, Long index) {
        return redisTemplate.opsForList().index(key, index);
    }

    @Override
    public List<String> getArray(String key, Long start, Long end) {
        return redisTemplate.opsForList().range(key, start, end);
    }

    @Override
    public Long getArraySize(String key) {
        return redisTemplate.opsForList().size(key);
    }

    @Override
    public Long getExpireTime(String key) {
        return redisTemplate.getExpire(key);
    }

    @Override
    public Map<String, String> getMap(String key) {
        Map<Object, Object> map = redisTemplate.opsForHash().entries(key);
        if(map==null || map.isEmpty()){
            return null;
        }
        Map<String, String> result = new HashMap<>();
        Set<Entry<Object, Object>> entry = map.entrySet();
        for (Entry<Object, Object> en : entry) {
            result.put(en.getKey().toString(), en.getValue().toString());
        }
        return result;
    }

    @Override
    public String getMap(String key, String key1) {
        Object object = redisTemplate.opsForHash().get(key, key1);
        if(object == null){
            return null;
        }
        return object.toString();
    }

    @Override
    public Set<String> getMapKeys(String key) {
        Set<Object> set = redisTemplate.opsForHash().keys(key);
        if(set==null || set.isEmpty()){
            return null;
        }
        Set<String> result = new HashSet<>();
        set.forEach(s -> {result.add(s.toString());});
        return result;
    }

    @Override
    public Long getMapSize(String key) {
        return redisTemplate.opsForHash().size(key);
    }

    @Override
    public List<String> getMapVals(String key) {
        List<Object> list = redisTemplate.opsForHash().values(key);
        if(list==null || list.isEmpty()){
            return null;
        }
        List<String> result = new ArrayList<>();
        list.forEach(s -> {result.add(s.toString());});
        return result;
    }

    @Override
    public <T> T getObj(String key, Class<T> clazz) {
        String json = redisTemplate.opsForValue().get(key);
        return JSONObject.parseObject(json,clazz);
    }

    @Override
    public void incr(String key) {
        incr(key, 1);
    }

    @Override
    public void incr(String key, Number val) {
        if(val instanceof Double){
            redisTemplate.opsForValue().increment(key, val.doubleValue());
        }else{
            redisTemplate.opsForValue().increment(key, val.intValue());
        }
    }

    @Override
    public boolean isExists(String key) {
        return redisTemplate.hasKey(key);
    }

    @Override
    public boolean lock(String key) {
        return lock(key, 3000L);
    }

    @Override
    public boolean lock(String key, long time) {
        return lock(key, key, time);
    }

    @Override
    public boolean lock(String key, String flag, long time) {
        return redisTemplate.opsForValue().setIfAbsent(key, flag, time, TimeUnit.MILLISECONDS);
    }

    @Override
    public String removeArrayLeft(String key) {
        return redisTemplate.opsForList().leftPop(key);
    }

    @Override
    public String removeArrayRight(String key) {
        return redisTemplate.opsForList().rightPop(key);
    }

    @Override
    public void removeArrayVal(String key, String val) {
        redisTemplate.opsForList().remove(key, 0, val);
    }

    @Override
    public void set(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    @Override
    public void set(String key, int expireTime) {
        set(key, null, expireTime);
    }

    @Override
    public void set(String key, long expireAt) {
        set(key, null,expireAt);
    }

    @Override
    public void set(String key, String value, int expireTime) {
        set(key, value,expireTime,0L);
    }

    @Override
    public void set(String key, String value, long expireAt) {
        set(key, value,0,expireAt);
    }

    private void set(String key, String value,int expireTime, long expireAt){
        if(value!=null && value.length()>0){
            redisTemplate.opsForValue().set(key, value);
        }
        if(expireTime >0){
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
        }else if(expireAt > 0){
            redisTemplate.expireAt(key, new Date(expireAt));
        }
    }

    @Override
    public void setArray(String key, String... array) {
        redisTemplate.opsForList().rightPushAll(key, array);
    }

    @Override
    public void setArray(String key, long index, String value) {
        redisTemplate.opsForList().set(key, index, value);
    }

    @Override
    public void setMap(String key, Map<String, String> map) {
        redisTemplate.opsForHash().putAll(key, map);
    }

    @Override
    public void setMap(String key, String key1, String value) {
        redisTemplate.opsForHash().put(key, key1, value);
    }

    @Override
    public <T> void setObj(String key, T obj) {
        set(key, JSONObject.toJSONString(obj));
    }

    @Override
    public <T> void setObj(String key, T obj, long expireAt) {
        set(key, JSONObject.toJSONString(obj),0,expireAt);
    }

    @Override
    public <T> void setObj(String key, T obj, int expireTime) {
        set(key, JSONObject.toJSONString(obj),expireTime,0L);
    }

    @Override
    public boolean unlock(String key) {
        return unlock(key, key);
    }

    @Override
    public void deleteByPrex(String prex) {
        Set<String> keys = keys(prex);
        String[] array = new String[keys.size()];
        keys.toArray(array);
        delete(array);
    }

    private Set<String> keys(String prex){
        Set<String> keys = redisTemplate.keys(prex);
        if(keys==null){
            return new HashSet<>();
        }
        return keys;
    }

    @Override
    public boolean unlock(String key, String flag) {
        //暂不做权限，仅删除key
        delete(key);
        return true;
    }

}
